package com.itheima.hash;
 
import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;
 
/**
 * 不带虚拟节点的一致性Hash算法
 */
public class ConsistentHashingWithoutVirtualNode {
 
	//服务器列表
	private static String[] servers = { "192.168.0.0", "192.168.0.1",
			"192.168.0.2", "192.168.0.3", "192.168.0.4" };
 
	//key表示服务器的hash值，value表示服务器
	private static SortedMap<Integer, String> serverMap = new TreeMap<Integer, String>();
 
	static {
		for (int i=0; i<servers.length; i++) {
			int hash = getHash(servers[i]);
			//理论上，hash环的最大值为2^32
			//这里为做实例，将ip末尾作为上限也就是254
			//那么服务器是0-4，乘以60后可以均匀分布到 0-254 的环上去
			//实际的请求ip到来时，在环上查找即可
			hash *= 60;
			System.out.println("add " + servers[i] + ", hash=" + hash);
			serverMap.put(hash, servers[i]);
		}
	}
 
	//查找节点
	private static String getServer(String key) {
		int hash = getHash(key);
		//得到大于该Hash值的所有server
		SortedMap<Integer, String> subMap = serverMap.tailMap(hash);
		if(subMap.isEmpty()){
			//如果没有比该key的hash值大的，则从第一个node开始
			Integer i = serverMap.firstKey();
			//返回对应的服务器
			return serverMap.get(i);
		}else{
			//第一个Key就是顺时针过去离node最近的那个结点
			Integer i = subMap.firstKey();
			//返回对应的服务器
			return subMap.get(i);
		}
	}
	
	//运算hash值
	//该函数可以自由定义，只要做到取值离散即可
	//这里取ip地址的最后一节
	private static int getHash(String str) {
		String last = str.substring(str.lastIndexOf(".")+1,str.length());
		return Integer.valueOf(last);
	}
 
	public static void main(String[] args) {
		//模拟5个随机ip请求
		for (int i = 0; i < 5; i++) {
			String ip = "192.168.0."+ new Random().nextInt(254);
			System.out.println(ip +" ---> "+getServer(ip));
		}
		//将5号服务器加到2-3之间，取中间位置，150
		System.out.println("add 192.168.0.5，hash=150");
		serverMap.put(150,"192.168.0.5");
		//再次发起5个请求
		for (int i = 0; i < 5; i++) {
			String ip = "192.168.0."+ new Random().nextInt(254);
			System.out.println(ip +" ---> "+getServer(ip));
		}
	}
}